#include <stdio.h>
#include <stdlib.h>

//声明节点结构
typedef struct Link {
    int elem;           //存储整形元素
    struct Link *next;  //指向直接后继元素的指针
}link;

//创建链表的函数
link* initLink() {
    link* p = malloc(sizeof(link)); //创建一个头结点
    //声明一个指针指向头结点，用于遍历链表
    link* temp = p;
    //生成链表
    for(int i = 1; i < 5; i++) {
        //创建节点并初始化
        link* a = malloc(sizeof(link));
        a->elem = i;
        a->next = NULL;
        //建立新节点与直接前驱节点的逻辑关系
        temp->next = a;
        temp = temp->next;
    }
    return p;
}

//p为原链表，elem表示新数据元素，index表示新元素要插入的位置
link* insertElem(link* p, int elem, int index) {
    //创建临时结点temp
    link* temp = p;
    for(int i=1; i<index; i++) {
        temp = temp->next;
        if(temp == NULL) {
            printf("插入位置无效\n");
            return p;
        }
    }
    //创建插入结点a
    link* a = malloc(sizeof(link));
    //向链表中插入结点
    a->elem = elem;
    a->next = temp->next;
    temp->next = a;
    return p;

}

//p为原链表，index为要删除元素的位置
link* delElem(link* p, int index) {
    //创建临时结点temp
    link* temp = p;
    //遍历到被删除结点的上一个结点
    for(int i=1; i<index; i++) {
        temp = temp->next;
        //判断被删除结点是否有后继结点
        if(temp->next == NULL) {
            printf("没有该结点\n");
            return p;
        }
    }
    //删除index结点
    //单独设置一个指针指向被删除结点，以防丢失
    link* del = temp->next;
    //删除某个结点的方法就是更改前一个结点的指针域
    temp->next = temp->next->next;
    //手动释放该结点，防止内存泄漏
    free(del);
    return p;
}

//p为原链表，elem表示被查找元素
int searchElem(link* p, int elem) {
    //创建临时结点temp
    link* temp = p;
    int index = 1;
    //遍历到被查找结点
    //由于头节点的存在，因此while中的判断为temp->next
    while (temp->next)
    {
        /* code */
        temp = temp->next;
        if(temp->elem == elem) {
            printf("查找到该元素\n");
            return index;
        }
        index++;
    }
    //程序执行至此处，表示查找失败
    return -1;
}

//更新函数，其中，index 表示更改结点在链表中的位置，elem 为新的数据域的值
link* updateElem(link* p, int index, int elem) {
    //创建临时结点temp
    link* temp = p;
    //tamp指向首元结点
    temp = temp->next;
    for(int i=1; i<index; i++) {
        //temp指向被删除结点
        temp = temp->next;
        if(temp == NULL) {
            printf("位置无效\n");
            return p;
        }
    }
    temp->elem = elem;
    return p;
}

void display(link *p);

int main(int argc, char* argv[]) {
    //初始化链表（1，2，3，4）
    printf("初始化链表为：\n");
    link* p = initLink();
    display(p);

    printf("在第4的位置插入元素5：\n");
    p = insertElem(p, 5, 4);
    display(p);

    printf("删除第3元素:\n");
    p = delElem(p, 3);
    display(p);

    printf("查找元素2的位置为：\n");
    int address = searchElem(p, 2);
    if(address == -1) {
        printf("没有该元素");
    } else {
        printf("元素2的位置为：%d\n", address);
    }

    printf("更改第3的位置上的数据为7:\n");
    p = updateElem(p, 3, 7);
    display(p);

    return 0;
}


void display(link *p) {
    link* temp = p;//将temp指针重新指向头结点
    //只要temp指针指向的结点的next不是Null，就执行输出语句。
    while (temp->next) {
        temp = temp->next;
        printf("%d ", temp->elem);
    }
    printf("\n");
}